import json
import logging
import re
import time
from urllib import request

import numpy
import tornado.gen
from cocoNLP.extractor import extractor

from backend.tools import log
from model import OcrHandle
import tornado.web
import requests
from PIL import Image
from io import BytesIO
from backend.tools.np_encoder import NpEncoder
from config import max_post_time, dbnet_max_size, white_ips

ocrhandle = OcrHandle()
logger = logging.getLogger(log.LOGGER_ROOT_NAME + '.' + __name__)
request_time = {}
# 加载数据模型
print('加载数据模型')
ex = extractor()
# 开始识别
print('开始识别')


class BusiPredictor(tornado.web.RequestHandler):
    '''
    业务操作接口
    '''

    def initialize(self):
        self.set_default_header()

    def get(self):
        self.set_status(404)
        self.write("404 : Please use POST")

    def set_default_header(self):
        self.set_header('Access-Control-Allow-Origin', '*')
        self.set_header('Access-Control-Allow-Headers', '*')
        self.set_header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS')
        self.set_header('Content-Type', 'application/json; charset=UTF-8')
        self.set_header('Access-Control-Allow-Headers', 'Content-Type')

    @tornado.gen.coroutine
    def post(self):
        '''
        :return:
        报错：
        400 没有请求参数
        '''
        short_size = 960
        res = []
        do_det = True
        remote_ip_now = self.request.remote_ip

        # 参数提取
        file_path = self.get_argument('path', None)
        print('path: ', file_path)
        pre_type = self.get_argument('pre_type', None)
        # 图片提取并转换
        try:
            yzmdata = requests.get(file_path)
            img = Image.open(BytesIO(yzmdata.content))
            if hasattr(img, '_getexif') and img._getexif() is not None:
                orientation = 274
                exif = dict(img._getexif().items())
                if orientation not in exif:
                    exif[orientation] = 0
                if exif[orientation] == 3:
                    img = img.rotate(180, expand=True)
                elif exif[orientation] == 6:
                    img = img.rotate(270, expand=True)
                elif exif[orientation] == 8:
                    img = img.rotate(90, expand=True)
        except Exception as ex:
            error_log = json.dumps({'code': 400, 'msg': '产生了一点错误，请检查日志', 'err': str(ex)}, cls=NpEncoder)
            logger.error(error_log, exc_info=True)
            self.finish(error_log)
            return
        img = img.convert("RGB")
        # 设置返回头
        self.set_header('content-type', 'application/json')
        # if remote_ip_now not in request_time:
        #     request_time[remote_ip_now] = 1
        # elif request_time[remote_ip_now] > max_post_time - 1 and remote_ip_now not in white_ips:
        #     res.append("今天访问次数超过{}次！".format(max_post_time))
        #     do_det = False
        # else:
        #     request_time[remote_ip_now] += 1
        short_size = 32 * (short_size // 32)
        img_w, img_h = img.size
        if max(img_w, img_h) * (short_size * 1.0 / min(img_w, img_h)) > dbnet_max_size:
            res.append("图片reize后长边过长，请调整短边尺寸")
            do_det = False

        if do_det:
            res = ocrhandle.text_predict(img, short_size)

        if pre_type == 'ID':
            pre_res = parse_id(res)
        elif pre_type == 'ID_FRONT':
            pre_res = judge_id_front(res)
        elif pre_type == 'ID_BACKEND':
            pre_res = judge_id_backend(res)
        else:
            pre_res = parse_license(res)
        time_now = time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime(time.time()))
        log_info = {
            'ip': self.request.remote_ip,
            'pre_type': pre_type,
            'return': pre_res,
            'time': time_now
        }
        logger.info(json.dumps(log_info, cls=NpEncoder))
        self.finish(json.dumps(
            {'code': 200, 'msg': '成功',
             'data': pre_res},
            cls=NpEncoder))
        return

    def options(self):
        pass


def parse_id(res):
    print('res: ', res)
    pre_res = {}
    pre_res['res'] = ''
    text = ''
    for i, item in enumerate(res):
        pre_res['res'] += item[1]
        item = item[1][3:].strip()
        text += item + ' '
        addr = ''
        if '名' in item:
            names = item.split('名')
            if names:
                pre_res['name'] = names[1]
            # name = item.strip().strip('姓名').strip('，').strip('牲名').strip('翔名').strip('名')
            # pre_res['name'] = name
        elif '性别' in item and '民族' in item:
            l_tmp = re.split('性别|民族', item)
            try:
                sex = l_tmp[1]
                nation = l_tmp[2]
                pre_res['sex'] = sex
                pre_res['nation'] = nation
            except Exception as e:
                pass
        elif '出生' in item:
            birth = item.strip('出生')
            pre_res['birth'] = birth
        elif '住址' in item:
            try:
                addr = item + res[i + 1][1][3:]
            except Exception as e:
                pass
        else:
            id_num = person_id_extract(item)
            if id_num:
                pre_res['id_no'] = id_num
        if not pre_res.get('name', ''):
            name = ex.extract_name(text)
            pre_res['name'] = name if name else ''
        pre_addr = addr.strip().strip("住址")
        pre_res['addr'] = pre_addr
        if not pre_res.get('addr', ''):
            locations = ex.extract_locations(text)
            pre_res['addr'] = locations[0] if locations else ''
    return pre_res


def parse_id_nlp(res):
    print('res: ', res)
    pre_res = {}
    text = ''
    for i, item in enumerate(res):
        item = item[1][3:]
        text += item
    names = ex.extract_name(text)
    addrs = ex.extract_locations(text)
    ids = ex.extract_ids(text)
    pre_res['name'] = names[0] if names else ''
    pre_res['addr'] = addrs[0] if addrs else ''
    pre_res['id_no'] = ids[0] if ids else ''
    return pre_res


def judge_id_front(res):  # 身份证正面信息提取
    pre_res = {}
    for i, item in enumerate(res):
        item = item[1][3:].strip()
        if '名' in item:
            pre_res['name'] = True
        elif '别' in item or '民族' in item:
            if '别' in item:
                pre_res['sex'] = True
            if '民族' in item:
                pre_res['nation'] = True
        elif '出生' in item:
            pre_res['birth'] = True
        elif '住址' in item:
            pre_res['addr'] = True
        else:
            id_num = person_id_extract(item)
            if id_num:
                pre_res['id_no'] = True

    return len(pre_res) >= 4


def judge_id_backend(res):  # 身份证反面面信息提取
    pre_res = 0
    for i, item in enumerate(res):
        item = item[1][3:].strip()
        if '中华人民' in item or '共和国' in item:
            pre_res += 1
        elif '居民' in item or '身份证' in item:
            pre_res += 1
        elif '签发' in item or '机关' in item:
            pre_res += 1
        elif '有效' in item or '期限' in item:
            pre_res += 1
        else:
            pass

    return pre_res >= 3


def parse_license(res):
    pre_res = {}
    text = ''
    for i, item in enumerate(res):
        text += item[1][3:] + ' '
        item = item[1][3:]
        code_pattern = re.compile(r'[0-9a-zA-Z]{16,18}')
        if ('称' in item or (ex.extract_locations(item) and len(item) < 16)) and not pre_res.get('com_name', ''):
            com_name = item.strip().strip('称').strip('，')
            pre_res['com_name'] = com_name
        elif code_pattern.search(item):
            code = code_pattern.search(item).group()
            pre_res['code'] = code
        elif '者' in item:
            owner = item.strip().strip('经营者').strip('营者').strip('者')
            pre_res['owner'] = owner
        else:
            pass
        if not pre_res.get('owner', ''):
            name = ex.extract_name(text)
            pre_res['owner'] = name if name else ''
    pre_res['pre_text'] = text
    return pre_res


def person_id_extract(text):
    # person_id = re.findall(r"^[A-Z\d]{15-18}$", text)
    person_id = re.findall(
        r"([1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])", text)
    per_id = ""
    if person_id:
        matrix = numpy.array(person_id)
        for i in matrix[:, 0]:
            per_id = per_id + ' ' + "".join(tuple(i))
    return per_id.strip()


def precidt_id(url, pre_type):
    short_size = 960
    res = []
    do_det = True

    # 参数提取
    file_path = url
    # 图片提取并转换
    try:
        yzmdata = requests.get(file_path)
        img = Image.open(BytesIO(yzmdata.content))
        if hasattr(img, '_getexif') and img._getexif() is not None:
            orientation = 274
            exif = dict(img._getexif().items())
            if orientation not in exif:
                exif[orientation] = 0
            if exif[orientation] == 3:
                img = img.rotate(180, expand=True)
            elif exif[orientation] == 6:
                img = img.rotate(270, expand=True)
            elif exif[orientation] == 8:
                img = img.rotate(90, expand=True)
    except Exception as ex:
        error_log = json.dumps({'code': 400, 'msg': '产生了一点错误，请检查日志', 'err': str(ex)}, cls=NpEncoder)
        logger.error(error_log, exc_info=True)
        return
    img = img.convert("RGB")

    short_size = 32 * (short_size // 32)
    img_w, img_h = img.size
    if max(img_w, img_h) * (short_size * 1.0 / min(img_w, img_h)) > dbnet_max_size:
        res.append("图片reize后长边过长，请调整短边尺寸")
        do_det = False

    if do_det:
        res = ocrhandle.text_predict(img, short_size)

    if pre_type == "ID":
        pre_res = parse_id(res)
        print('pre_res id:', pre_res)
        return pre_res.get('name', ''), pre_res.get('id_no', ''), pre_res.get('addr', '')
    else:
        pre_res = parse_license(res)
        print('pre_res license:', pre_res)
        return pre_res.get('com_name', ''), pre_res.get('code', ''), pre_res.get('owner', '')
